package com.utils
{
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.ProgressEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	import flash.utils.clearInterval;
	import flash.utils.getDefinitionByName;
	import flash.utils.setInterval;

	/**
	 * @author Xucan
	 */
	public class MusicUtil
	{
		private static var biggerBgChannel:SoundChannel;
		private static var sfxchannel:SoundChannel;
		private static var bgmSound:Sound;
		private static var bgmM4aNS:NetStream;
		private static var bgmM4aNC:NetConnection;
		private static var sfxDic:Dictionary = new Dictionary();
		private static var bgmDic:Dictionary = new Dictionary();
		private static var _isSfxOn:Boolean = true;
		private static var _isBgmOn:Boolean = true;
		private static var musicLoaded:Boolean;
		private static var _bgVolumn:Number = 0.5;
		private static var _effVolumn:Number = 0.5;
		private static var _isPlayingBgMusic:Boolean;
		private static var t1:int;
		public static var isSoundLoaded:Boolean;
		public static var curMusicName:String;
		private static var checkInterval:uint;

		public static function setVolumn( mainNum:uint, bgNum:uint, effNum:uint ):void
		{
			_bgVolumn = 0.01 * mainNum * 0.01 * bgNum;
			_effVolumn = 0.01 * mainNum * 0.01 * effNum;
			setBiggerBgVolume( _bgVolumn, bgmM4aNS );
			setEffVolume();
		}

		private static function setBiggerBgVolume( bgNum:Number, m4aNS:NetStream ):void
		{
			var transForm:SoundTransform;
			if (useM4a)
			{
				transForm = m4aNS.soundTransform;
				transForm.volume = bgNum;
				m4aNS.soundTransform = transForm;
			}
			else
			{
				transForm = new SoundTransform( bgNum );
				if (biggerBgChannel)
				{
					biggerBgChannel.soundTransform = transForm;
				}
			}
		}

		private static function setSmallerBgVolume( bgNum:Number, smallerChannel:SoundChannel, smallerBgm:NetStream ):void
		{
			if (useM4a)
			{
				setBiggerBgVolume( bgNum, smallerBgm );
			}
			else
			{
				var transForm:SoundTransform = new SoundTransform( bgNum );
				if (smallerChannel)
				{
					smallerChannel.soundTransform = transForm;
				}
			}
		}

		private static function setEffVolume():void
		{
			var transForm:SoundTransform = new SoundTransform( _effVolumn );
			if (sfxchannel)
			{
				sfxchannel.soundTransform = transForm;
			}
		}

		/**
		 * 是否开启音效
		 */
		public static function set isSfxOn( v:Boolean ):void
		{
			_isSfxOn = v;
		}

		public static function set isBgmOn( v:Boolean ):void
		{
			_isBgmOn = v;
			if (_isBgmOn)
			{
				try
				{
					playBgm();
				}
				catch(e:Error)
				{
				}
			}
			else
			{
				stopBgm();
			}
		}

		public static function get isBgmOn():Boolean
		{
			return _isBgmOn;
		}

		public static function get isSfxOn():Boolean
		{
			return _isSfxOn;
		}

		/**
		 * 创建一个音效
		 * @param factory 
		 * @return 如果音效被禁就返回空
		 */
		public static function playSfx( factory:Class ):void
		{
			if (_isSfxOn)
			{
				if (sfxDic[factory] == null)
				{
					sfxDic[factory] = new factory();
				}
				sfxchannel = sfxDic[factory].play();
				if (sfxchannel != null)
				{
					setEffVolume();
				}
			}
		}

		public static var cdn:String = "";
		public static var useM4a:Boolean = true;

		public static function loadOrPlayBgm( musicName:String ):void
		{
			if (!musicName) return;
			stopBgm();
			if (_isBgmOn)
			{
				curMusicName = musicName;
				if (bgmDic[musicName] == null)
				{
					var VerisonClass:Class = getDefinitionByName( "Verison" ) as Class;
					var Verison:* = VerisonClass.verDic;
					var url:String = cdn + "bgmusic/" + musicName;
					if (useM4a)
					{
						url += ".m4a";
						bgmM4aNC = new NetConnection();
						bgmM4aNC.connect( null );
						bgmM4aNS = new NetStream( bgmM4aNC );
						bgmM4aNS.bufferTime = 5;
						bgmM4aNS.client = { onMetaData:function( info:Object ):void
						{
							//trace( "metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate );
						} };
						bgmM4aNS.play( url );
						bgmDic[musicName] = bgmM4aNS;
						setBiggerBgVolume( 0, bgmM4aNS );
						bgmM4aNS.addEventListener( NetStatusEvent.NET_STATUS, onM4aStatus );
						clearInterval( checkInterval );
						checkInterval = setInterval( onPrg, 1000 );
					}
					else
					{
						url += ".mp3";
						bgmSound = new Sound();
						bgmSound.load( new URLRequest( url + "?v=" + Verison[url] ) );
						bgmDic[musicName] = bgmSound;
						bgmSound.addEventListener( ProgressEvent.PROGRESS, onPrg );
						bgmSound.addEventListener( Event.COMPLETE, onComplete );
						bgmSound.addEventListener( IOErrorEvent.IO_ERROR, function():void
						{
							trace( "加载声音失败！" );
						} );
					}

					return;
				}
				if (!musicLoaded)
				{
					closeBgm();
				}
				if (useM4a) bgmM4aNS = bgmDic[musicName];
				else bgmSound = bgmDic[musicName];
				playBgm();
			}
		}

		private static function onM4aStatus( event:NetStatusEvent ):void
		{
			switch( event.info.code )
			{
				case "NetStream.Buffer.Full":
					musicLoaded = true;
					break;
				case "NetStream.Play.Stop":
					bgmM4aNS.seek( 0 );
					break;
			}
		}

		private static function onComplete( e:Event ):void
		{
			musicLoaded = true;
		}

		private static function onPrg( e:ProgressEvent = null ):void
		{
			if (useM4a)
			{
				if (bgmM4aNS.bytesLoaded >= bgmM4aNS.bufferLength)
				{
					playBgm();
					clearInterval( checkInterval );
				}
			}
			else
			{
				var pct:int = Math.round( bgmSound.bytesLoaded * 100 / bgmSound.bytesTotal );
				trace( "进度：" + pct + "%" );
				if (pct > 5)
				{
					playBgm();
					bgmSound.removeEventListener( ProgressEvent.PROGRESS, onPrg );
				}
			}
		}

		private static function onPlayend( e:Event ):void
		{
			trace( "播放完成" );
			playBgmAgain();
		}

		private static function playBgmAgain():void
		{
			if (bgmSound || bgmM4aNS)
			{
				try
				{
					if (useM4a)
					{
						bgmM4aNS.resume();
						bgmM4aNS.seek( 0 );
						setBiggerBgVolume( _bgVolumn, bgmM4aNS );
					}
					else
					{
						biggerBgChannel = bgmSound.play();
						if (biggerBgChannel != null)
						{
							setBiggerBgVolume( _bgVolumn, bgmM4aNS );
							biggerBgChannel.addEventListener( Event.SOUND_COMPLETE, onPlayend );
						}
					}
				}
				catch (error:IOError)
				{
					trace( "musicplay失败！" );
				}
			}
		}

		private static function playBgm():void
		{
			if (bgmSound || bgmM4aNS && !_isPlayingBgMusic)
			{
				if (!useM4a)
					biggerBgChannel = bgmSound.play();
				else
				{
					bgmM4aNS.resume();
					bgmM4aNS.seek( 0 );
				}
				_isPlayingBgMusic = true;
				try
				{
					if (bgmM4aNS || biggerBgChannel != null )
					{
						setBiggerBgVolume( 0, bgmM4aNS );
						clearInterval( t1 );
						var num:Number = 0;
						var currentM4aNS:NetStream = bgmM4aNS;
						t1 = setInterval( function():void
						{
							setBiggerBgVolume( _bgVolumn * num * (num++ ) * 0.1 * 0.1, currentM4aNS );
							if (num >= 10)
							{
								clearInterval( t1 );
							}
						}, 500 );
						if (biggerBgChannel)
							biggerBgChannel.addEventListener( Event.SOUND_COMPLETE, onPlayend );
					}
				}
				catch (error:IOError)
				{
					trace( "musicplay失败！" );
				}
			}
		}

		private static function stopBgm():void
		{
			if ((bgmM4aNS || biggerBgChannel) && _isPlayingBgMusic)
			{
				var smallerBgChannel:SoundChannel = biggerBgChannel;
				var smallerBgm:NetStream = bgmM4aNS;
				_isPlayingBgMusic = false;
				try
				{
					var t2:uint;
					var num:Number = 10;
					t2 = setInterval( function():void
					{
						setSmallerBgVolume( _bgVolumn * num * (num-- ) * 0.1 * 0.1, smallerBgChannel, smallerBgm );
						if (num <= 0)
						{
							clearInterval( t2 );
							if (smallerBgm) smallerBgm.pause();
							if (smallerBgChannel)
							{
								smallerBgChannel.stop();
								smallerBgChannel = null;
							}
						}
					}, 150 );
				}
				catch (error:IOError)
				{
					trace( "musicstop失败！" );
				}
			}
		}

		private static function closeBgm():void
		{
			if (bgmM4aNS)
			{
				try
				{
					bgmM4aNS.pause();
				}
				catch (error:IOError)
				{
					trace( "musicclose失败！" );
				}
			}
			if (bgmSound)
			{
				try
				{
					bgmSound.close();
				}
				catch (error:IOError)
				{
					trace( "musicclose失败！" );
				}
			}
		}
	}
}
